home *** CD-ROM | disk | FTP | other *** search
/ Linux Cubed Series 2: Applications / Linux Cubed Series 2 - Applications.iso / circuits / irsim-9.000 / irsim-9 / src / irsim / eval.c < prev    next >
C/C++ Source or Header  |  1993-01-15  |  13KB  |  509 lines

  1. /* 
  2.  *     ********************************************************************* 
  3.  *     * Copyright (C) 1988, 1990 Stanford University.                     * 
  4.  *     * Permission to use, copy, modify, and distribute this              * 
  5.  *     * software and its documentation for any purpose and without        * 
  6.  *     * fee is hereby granted, provided that the above copyright          * 
  7.  *     * notice appear in all copies.  Stanford University                 * 
  8.  *     * makes no representations about the suitability of this            * 
  9.  *     * software for any purpose.  It is provided "as is" without         * 
  10.  *     * express or implied warranty.  Export of this software outside     * 
  11.  *     * of the United States of America may require an export license.    * 
  12.  *     ********************************************************************* 
  13.  */
  14.  
  15. #include <stdio.h>
  16. #include "defs.h"
  17. #include "net.h"
  18. #include "globals.h"
  19.  
  20.  
  21. /*
  22.  * simulator can use one of several models, selectable by the user.  Which
  23.  * model to use is kept as index into various dispatch tables, all defined
  24.  * below.
  25.  */
  26. public
  27. #define    LIN_MODEL    0
  28. public
  29. #define    SWT_MODEL    1
  30. public
  31. #define    NMODEL        2        /* number of models supported */
  32.  
  33.  
  34. public void (*model_table[NMODEL])() =    /* model dispatch table */
  35.   {
  36.     linear_model, switch_model
  37.   };
  38.  
  39.  
  40. public    int    model_num = LIN_MODEL;        /* index of model in table */
  41. public    void    (*model)() = linear_model;    /* evaluation model */
  42. public    int    sm_stat = NORM_SIM;        /* simulation status */
  43. public    int    treport = 0;            /* report format */
  44.  
  45. private    int    firstcall = 1;        /* reset when calling init_vdd_gnd */
  46. private    struct Node nd_no_inp;
  47.  
  48.  
  49. /*
  50.  * find transistors with gates of VDD or GND and calculate values for source
  51.  * and drain nodes just in case event driven calculations don't get to them.
  52.  */
  53. private void init_vdd_gnd()
  54.   {
  55.     enqueue_input( VDD_node, HIGH );
  56.     enqueue_input( GND_node, LOW );
  57.  
  58.     firstcall = 0;        /* initialization now taken care of */
  59.   }
  60.  
  61. /*
  62.  * Reset the firstcall flag.  Usually after reading history dump or net state
  63.  */
  64. public void NoInit()
  65.   {
  66.     firstcall = 0;
  67.   }
  68.  
  69.  
  70. /*
  71.  * Set the firstcall flags.  Used when moving back to time 0.
  72.  */
  73. public void ReInit()
  74.   {
  75.     firstcall = 1;
  76.   }
  77.  
  78. /*
  79.  * Print decay event.
  80.  */
  81. private void pr_decay( e )
  82.   evptr  e;
  83.   {
  84.     nptr  n = e->enode;
  85.  
  86.     lprintf( stdout, " @ %.1fns %s: decay %c -> X\n",
  87.       d2ns( e->ntime ), pnode( n ), vchars[ n->npot ] );
  88.   }
  89.  
  90.  
  91. /*
  92.  * Print watched node event.
  93.  */
  94. private void pr_watched( e, n )
  95.   evptr  e;
  96.   nptr   n;
  97.   {
  98.     int   tmp;
  99.  
  100.     if( n->nflags & INPUT )
  101.       {
  102.     lprintf( stdout, " @ %.1fns input %s: -> %c\n",
  103.       d2ns( e->ntime ), pnode( n ), vchars[ e->eval ] );
  104.     return;
  105.       }
  106.  
  107.     tmp = (debug & DEBUG_EV) ? (REPORT_TAU | REPORT_DELAY) : treport;
  108.  
  109.     lprintf( stdout, " @ %.1fns %s: %c -> %c",
  110.       d2ns( e->ntime ), pnode( n ), vchars[ n->npot ], vchars[ e->eval ] );
  111.  
  112.     switch( tmp & (REPORT_TAU | REPORT_DELAY) )
  113.       {
  114.     case 0 :
  115.         lprintf( stdout, "\n" );                    break;
  116.     case REPORT_TAU :
  117.         lprintf( stdout, " (tau=%.1fns)\n", d2ns( e->rtime ) );    break;
  118.     case REPORT_DELAY :
  119.         lprintf( stdout, " (delay=%.1fns)\n", d2ns( e->delay ) );    break;
  120.     default :
  121.         lprintf( stdout, " (tau=%.1fns, delay=%.1fns)\n",
  122.           d2ns( e->rtime ), d2ns( e->delay ) );
  123.       }
  124.   }
  125.  
  126.  
  127. /*
  128.  * Run through the event list, marking all nodes that need to be evaluated.
  129.  */
  130. private void MarkNodes( evlist )
  131.   evptr  evlist;
  132.   {
  133.     register nptr   n;
  134.     register tptr   t;
  135.     register lptr   l;
  136.     register evptr  e = evlist;
  137.     long            all_flags = 0;
  138.                     
  139.     do
  140.       {
  141.     n = e->enode;
  142.  
  143.     all_flags |= n->nflags;
  144.  
  145.     if( e->type == DECAY_EV and ( (treport & REPORT_DECAY) or
  146.       (n->nflags & (WATCHED | STOPONCHANGE)) ) )
  147.         pr_decay( e );
  148.     else if( n->nflags & (WATCHED | STOPONCHANGE) )
  149.         pr_watched( e, n );
  150.  
  151.     n->npot = e->eval;
  152.  
  153.         /* Add the new value to the history list (if they differ) */
  154.     if( not (n->nflags & INPUT) and (n->curr->val != n->npot) )
  155.         AddHist( n, n->npot, 0, (long) e->ntime, (long) e->delay,
  156.           (long) e->rtime );
  157.  
  158. #ifdef STATS
  159.     { extern int ev_hgm; if( ev_hgm ) IncHistEvCnt( -1 ); }
  160. #endif STATS
  161.  
  162.         /* for each transistor controlled by event node, mark 
  163.          * source and drain nodes as needing recomputation.
  164.          *
  165.          * Added MOSSIMs speed up by first checking if the 
  166.          * node needs to be rechecked  mh
  167.          *
  168.          * Fixed it so nodes with pending events also get
  169.          * re_evaluated. Kevin Karplus
  170.          */
  171.     for( l = n->ngate; l != NULL; l = l->next )
  172.       {
  173. #ifdef notdef
  174.         char  oldstate;
  175.  
  176.         t = l->xtor;
  177.         /*
  178.          * Some of these optimizations only work right when the
  179.          * stage at the src/drn contains no loops.  For example,
  180.          * when a transistor turns off and the src=1 and drn=0,
  181.          * the transistor may break a previous loop causing the
  182.          * src or drn to change value.
  183.          * 
  184.          * Also, while the state of the src/drn of the transistor
  185.          * in question may not change state, the current through
  186.          * their stage is altered; this current change may change
  187.          * the state of other nodes in the stage, so they better
  188.          * be avaluated.  These optimizations work best in MOSSIM
  189.          * since that model does not account for the current through
  190.          * the stage.    A.S.
  191.          */
  192.         oldstate = t->state;
  193.  
  194.         t->state = compute_trans_state( t );
  195.         if( (t->drain->npot == X) or (t->source->npot == X) or
  196.           ((t->drain->npot != t->source->npot) and
  197.           (t->state == ON)) or
  198.           ((t->drain->npot == t->source->npot) and
  199.           (t->state == OFF)) or
  200.           ((t->state == UNKNOWN) and
  201.           not (oldstate == OFF and
  202.           (t->drain->npot == t->source->npot))) or
  203.           (t->drain->events != NULL) or
  204.           (t->source->events != NULL) )
  205.           {
  206.         if( not (t->source->nflags & INPUT) )
  207.             t->source->nflags |= VISITED;
  208.         if( not (t->drain->nflags & INPUT) )
  209.             t->drain->nflags |= VISITED;
  210.           }
  211. #else
  212.         t = l->xtor;
  213.         t->state = compute_trans_state( t );
  214.         if( not (t->source->nflags & INPUT) )
  215.         t->source->nflags |= VISITED;
  216.         if( not (t->drain->nflags & INPUT) )
  217.         t->drain->nflags |= VISITED;
  218. #endif
  219.       }
  220.     free_from_node( e, n );    /* remove to avoid punting this event */
  221.     e = e->flink;
  222.       }
  223.     while( e != NULL );
  224.  
  225.     /* run thorugh event list again, marking src/drn of input nodes */
  226.     if( all_flags & INPUT )
  227.       {
  228.     for( e = evlist; e != NULL; e = e->flink )
  229.       {
  230.         n = e->enode;
  231.  
  232.         if( (n->nflags & (INPUT | POWER_RAIL)) != INPUT )
  233.         continue;
  234.         
  235.         for( l = n->nterm; l != NULL; l = l->next )
  236.           {
  237.         t = l->xtor;
  238.         if( t->state != OFF )
  239.           {
  240.             register nptr other = other_node( t, n );
  241.             if( not( other->nflags & (INPUT | VISITED) ) )
  242.             other->nflags |= VISITED;
  243.           }
  244.           }
  245.       }
  246.       }
  247.   }
  248.  
  249.  
  250. private long EvalNodes( evlist )
  251.   evptr  evlist;
  252.   {
  253.     register tptr   t;
  254.     register lptr   l;
  255.     register nptr   n;
  256.     register evptr  event = evlist;
  257.     long            brk_flag = 0;
  258.  
  259.     do
  260.       {
  261.     nevent += 1;        /* advance counter to that of this event */
  262.     n = cur_node = event->enode;
  263.     n->c.time = event->ntime;    /* set up the cause stuff */
  264.     n->t.cause = event->p.cause;
  265.  
  266.     npending -= 1;
  267.  
  268.       /* now calculate new value for each marked node.  Some nodes marked
  269.        * above may become unmarked by earlier calculations before we get
  270.        * to them in this loop...
  271.        */
  272.  
  273.     for( l = n->ngate; l != NULL; l = l->next )
  274.       {
  275.         t = l->xtor;
  276.         if( t->source->nflags & VISITED )
  277.         (*model)( t->source );
  278.         if( t->drain->nflags & VISITED )
  279.         (*model)( t->drain );
  280.       }
  281.  
  282.     if( (n->nflags & (INPUT | POWER_RAIL)) == INPUT )
  283.       {
  284.         for( l = n->nterm; l != NULL; l = l->next )
  285.           {
  286.         nptr  other;
  287.  
  288.         t = l->xtor;
  289.         other = other_node( t, n );
  290.         if( other->nflags & VISITED )
  291.             (*model)( other );
  292.           }
  293.       }
  294.  
  295.         /* see if we want to halt if this node changes value */
  296.     brk_flag |= n->nflags;
  297.  
  298.     event = event->flink;
  299.       }
  300.     while( event != NULL );
  301.  
  302.     return( brk_flag );
  303.   }
  304.  
  305.  
  306. /*
  307.  * Change the state of the nodes in the given input list to their new value,
  308.  * setting their INPUT flag and enqueueing the event.
  309.  */
  310. private void SetInputs( listp, val )
  311.   register iptr  *listp;
  312.   register int   val;
  313.   {
  314.     register nptr  n, other;
  315.     register lptr  l;
  316.     register tptr  t;
  317.     iptr           ip, last;
  318.  
  319.     for( ip = last = *listp; ip != NULL; ip = ip->next )
  320.       {
  321.     last = ip;
  322.  
  323.     n = ip->inode;
  324.  
  325.     n->npot = val;
  326.     n->nflags &= ~INPUT_MASK;
  327.     n->nflags |= INPUT;
  328.  
  329.         /* enqueue event so consequences are computed. */
  330.     enqueue_input( n, val );
  331.  
  332.     if( n->curr->val != val or not (n->curr->inp) )
  333.         AddHist( n, val, 1, cur_delta, 0L, 0L );
  334.       }
  335.  
  336.     if( last )
  337.       {
  338.     last->next = infree;
  339.     infree = *listp;
  340.       }
  341.     *listp = NULL;
  342.   }
  343.  
  344.  
  345. private void MarkNOinputs()
  346.   {
  347.     register iptr  list;
  348.  
  349.     for( list = xinputs; list != NULL; list = list->next )
  350.       {
  351.     list->inode->nflags &= ~(INPUT_MASK | INPUT);
  352.     list->inode->nflags |= VISITED;
  353.       }
  354.   }
  355.  
  356.  
  357.     /* nodes which are no longer inputs */
  358. private void EvalNOinputs()
  359.   {
  360.     nptr  n;
  361.     iptr  list, last;
  362.  
  363.     for( list = last = xinputs; list != NULL; list = list->next )
  364.       {
  365.     cur_node = n = list->inode;
  366.     AddHist( n, (int) n->curr->val, 0, cur_delta, 0L, 0L );
  367.     if( n->nflags & VISITED )
  368.         (*model)( n );
  369.     last = list;
  370.       }
  371.     if( last )
  372.       {
  373.     last->next = infree;
  374.     infree = xinputs;
  375.       }
  376.     xinputs = NULL;
  377.   }
  378.  
  379.  
  380. public int step( stop_time )
  381.   long  stop_time;
  382.   {
  383.     evptr  evlist;
  384.     long   brk_flag;
  385.     int    ret_code = 0;
  386.  
  387.     /* look through input lists updating any nodes which just become inputs */
  388.  
  389.     MarkNOinputs();            /* nodes no longer inputs */
  390.     SetInputs( &hinputs, HIGH );    /* HIGH inputs */
  391.     SetInputs( &linputs, LOW );        /* LOW inputs */
  392.     SetInputs( &uinputs, X );        /* X inputs */
  393.  
  394.     /* 
  395.      * On the first call to step, make sure transistors with gates
  396.      * of vdd and gnd are set up correctly.  Mark initial inputs first!
  397.      */
  398.     if( firstcall )
  399.     init_vdd_gnd();
  400.  
  401.   try_again :
  402.     /* process events until we reach specified stop time or events run out. */
  403.     while( (evlist = get_next_event( stop_time )) != NULL )
  404.       {
  405.     MarkNodes( evlist );
  406.     if( xinputs ) EvalNOinputs();
  407.  
  408.     brk_flag = EvalNodes( evlist );
  409.  
  410.     FreeEventList( evlist );    /* return event list to free pool */
  411.  
  412.     if( int_received )
  413.         goto done;
  414.     if( brk_flag & (WATCHVECTOR | STOPONCHANGE | STOPVECCHANGE) )
  415.       {
  416.         if( brk_flag & (WATCHVECTOR | STOPVECCHANGE) )
  417.         disp_watch_vec( brk_flag );
  418.         if( brk_flag & (STOPONCHANGE | STOPVECCHANGE) )
  419.           {
  420.         ret_code = 1;
  421.         goto done;
  422.           }
  423.       }
  424.       }
  425.  
  426.     if( xinputs )
  427.       {
  428.     EvalNOinputs();
  429.     goto try_again;
  430.       }
  431.  
  432.     cur_delta = stop_time;
  433.   done :
  434.     if( analyzerON )
  435.     UpdateWindow( cur_delta );
  436.     return( ret_code );
  437.   }
  438.  
  439.  
  440. /* table to convert transistor type and gate node value into switch state
  441.  * indexed by switch_state[transistor-type][gate-node-value].
  442.  */
  443. public    char  switch_state[NTTYPES][4] = 
  444.   {
  445.     OFF,    UNKNOWN,    UNKNOWN,    ON,    /* NCHAH */
  446.     ON,        UNKNOWN,    UNKNOWN,    OFF,    /* PCHAN */
  447.     WEAK,    WEAK,        WEAK,        WEAK,   /* RESIST */
  448.     WEAK,    WEAK,        WEAK,        WEAK,   /* DEP */
  449.   };
  450.  
  451.  
  452. /* compute state of transistor.  If gate is a simple node, state is determined
  453.  * by type of implant and value of node.  If gate is a list of nodes, then
  454.  * this transistor represents a stack of transistors in the original network,
  455.  * and we perform the logical AND of all the gate node values to see if
  456.  * transistor is on.
  457.  */
  458. public
  459. #define     compute_trans_state( TRANS )                    \
  460.     ( ((TRANS)->ttype & GATELIST) ?                    \
  461.     ComputeTransState( TRANS ):                    \
  462.     switch_state[ BASETYPE( (TRANS)->ttype ) ][ (TRANS)->gate->npot ] )
  463.  
  464.  
  465. public int ComputeTransState( t )
  466.   register tptr  t;
  467.   {
  468.     register nptr  n;
  469.     register tptr  l;
  470.     register int   result;
  471.  
  472.     switch( BASETYPE( t->ttype ) )
  473.       {
  474.     case NCHAN :
  475.         result = ON;
  476.         for( l = (tptr) t->gate; l != NULL; l = l->scache.t )
  477.           {
  478.         n = l->gate;
  479.         if( n->npot == LOW )
  480.             return( OFF );
  481.         else if( n->npot == X )
  482.             result = UNKNOWN;
  483.           }
  484.         return( result );
  485.  
  486.     case PCHAN :
  487.         result = ON;
  488.         for( l = (tptr) t->gate; l != NULL; l = l->scache.t )
  489.           {
  490.         n = l->gate;
  491.         if( n->npot == HIGH )
  492.             return( OFF );
  493.         else if( n->npot == X )
  494.             result = UNKNOWN;
  495.           }
  496.         return( result );
  497.  
  498.     case DEP :
  499.     case RESIST :
  500.         return( WEAK );
  501.  
  502.     default :
  503.         lprintf( stderr,
  504.           "**** internal error: unrecongized transistor type (0x%x)\n",
  505.           BASETYPE( t->ttype ) );
  506.         return( UNKNOWN );
  507.       }
  508.   }
  509.